package it.mauriziobasile.andoid.aub.su;

import it.mauriziobasile.andoid.aub.utils.Logger;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RootUtils {
    private static final String HOSTS_FILE_NAME = "/etc/hosts";
    private static final String ORIG_HOSTS_FILE_NAME = "/etc/hosts.original";

    public static boolean hasBackup() throws IOException, InterruptedException {
        File origFile = new File(ORIG_HOSTS_FILE_NAME);
        return origFile.exists();
    }

    public static int restoreHostsFile() throws IOException, InterruptedException {
        File origFile = new File(ORIG_HOSTS_FILE_NAME);
        if (!origFile.exists())
            return -1;
        int exit = 0;
        exit += mountSystemRW();
        exit += executeCommandAsRoot("cat " + ORIG_HOSTS_FILE_NAME + " > " + HOSTS_FILE_NAME);
        exit += executeCommandAsRoot("rm " + ORIG_HOSTS_FILE_NAME);
        exit += mountSystemRO();
        return exit;
    }

    public static int backupHostsFile() throws IOException, InterruptedException {
        File origFile = new File(ORIG_HOSTS_FILE_NAME);
        if (origFile.exists())
            return 0;
        int exit = 0;
        exit += mountSystemRW();
        exit += executeCommandAsRoot("cat " + HOSTS_FILE_NAME + " > " + ORIG_HOSTS_FILE_NAME);
        exit += mountSystemRO();
        return exit;
    }

    private static String[] getSystemDevice() throws IOException {
        String mountFile = "/proc/mounts";
        FileReader file = new FileReader(mountFile);
        BufferedReader reader = new BufferedReader(file);
        Pattern patt = Pattern.compile("([^\\s]+) /system ([^\\s]+) (.*)");
        String line = reader.readLine();
        while (line != null) {
            Matcher mat = patt.matcher(line);
            if (mat.matches() && mat.groupCount() == 3) {
                String[] sd = new String[2];
                sd[0] = mat.group(1);
                sd[1] = mat.group(2);
                Logger.d("system mount  is from " + sd[0]);
                return sd;
            }
            line = reader.readLine();
        }
        return null;
    }

    private static int mountSystemRW() throws IOException, InterruptedException {
        String[] sd = getSystemDevice();
        if (sd != null) {
            Logger.d("remount system rw (" + sd[0] + " - " + sd[1] + ")");
            // mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system
            return executeCommandAsRoot("mount -o rw,remount -t " + sd[1] + " " + sd[0] + " /system");
        } else {
            Logger.e("Unable to get system device");
        }
        return -1;
    }

    private static int mountSystemRO() throws IOException, InterruptedException {
        String[] sd = getSystemDevice();
        if (sd != null) {
            Logger.d("remount system ro (" + sd[0] + " - " + sd[1] + ")");
            // mount -o ro,remount -t yaffs2 /dev/block/mtdblock3 /system
            return executeCommandAsRoot("mount -o ro,remount -t " + sd[1] + " " + sd[0] + " /system");
        } else {
            Logger.e("Unable to get system device");
        }
        return -1;
    }

    private static int executeCommandAsRoot(String command) throws IOException, InterruptedException {
        Logger.d("Excec command(" + command + ") as root");
        int exit = 0;
        Process process = Runtime.getRuntime().exec("su");
        DataOutputStream outputStream = new DataOutputStream(process.getOutputStream());
        // DataInputStream inputStream = new
        // DataInputStream(process.getInputStream());
        outputStream.writeBytes(command + "\n");
        outputStream.flush();
        outputStream.writeBytes("exit\n");
        outputStream.flush();
        exit += process.waitFor();
        return exit;
    }

}
